<?php
// @formatter:off
/**
 * @file WCCollectionsHolder.php
 * @author Alejandro Dario Simi
 * @date $Date: 2013-06-04 03:02:53 +0000 (Tue, 04 Jun 2013) $
 *
 * $Id: WCCollectionsHolder.php 68 2013-06-04 03:02:53Z daemonraco@gmail.com $
 * $URL: http://wcomix.googlecode.com/svn/tags/wcomix-1.0-BETA1/includes/holders/WCCollectionsHolder.php $
 */
// @formatter:on

require_once "{$wcPaths["includes-directory"]}/representations/WCCollection.php";

/**
 * @class WCCollectionsHolder
 * This class is a holder for representations of table '%collections', in other
 * words, a holder for WCCollection objects.
 */
class WCCollectionsHolder extends WCGHolder {
	/**
	 * @var WCCollectionsHolder Pointer to the singleton instance.
	 */
	protected static $_Instance;
	/**
	 * @var string Class name of the objects to be held.
	 */
	protected $_PropertiesItemClass = "WCCollection";
	/**
	 * @var string This is the prefix of every column on the table
	 * '%collections'.
	 */
	protected $_PropertiesPrefix = "col_";
	/**
	 * @var string This is the name of the table represented by WCCollection
	 * objects. In this case, '%collections'.
	 */
	protected $_PropertiesTable = "collections";
	/**
	 * @var boolean This flag indicates that more than one collection may have
	 * the same name.
	 */
	protected $_PropertiesDupNames = true;
	/**
	 * @var WCCollection[] A collection holder must have, not only the full
	 * list of WCCollection objects, but also the list of those collections
	 * at the top of any tree. This is the list of those collections.
	 */
	protected $_topItems = array();
	//
	// Public methods
	/**
	 * This method looks for a collection with certain path.
	 *
	 * @param string $path Collection path to look for.
	 * @param WCGroup $group Found collection must also match this group.
	 * @return WCCollection Returns a collection that matches the path.
	 */
	public function itemByPath($path, WCGroup &$group) {
		//
		// Setting a default value to be returned.
		$out = null;
		//
		// Checking that $path is at least something like '/something'.
		if(strlen($path) > 1 && substr($path, 0, 1) == "/") {
			//
			// Getting all parts of the path to search.
			$pathParts = explode(WCCollection::$PathSeparator, $path);
			//
			// Getting those collection that match the base-name of the path
			// to look for.
			$keyword = $pathParts[count($pathParts) - 1];
			foreach($this->collectionsLike($keyword, $group) as $collection) {
				if($collection->path() == $path) {
					//
					// At this point, a collection was found.
					$out = $collection;
					// This loop must stop here.
					break;
				}
			}
			//
			// If it wasn't found yet, a full scan is performed.
			if($out === null) {
				//
				// Looking inside every top collection sub-tree.
				foreach($this->topItems($group) as $topCollection) {
					//
					// Looking inside a each sub-tree.
					foreach($topCollection->collectionsFull() as $collection) {
						//
						// Checking for a match, when
						// found, this loop will break.
						if($collection->path() == $path) {
							//
							// At this point, a
							// collection was found.
							$out = $collection;
							// This loop must stop
							// here.
							break;
						}
					}
					//
					// If something was found, this loop must
					// stop.
					if($out !== null) {
						break;
					}
				}
			}
		}
		//
		// Returning results.
		return $out;
	}
	/**
	 * This method looks for collections that match, at least partially with a
	 * keyword.
	 *
	 * @param string $keywords Word to look for.
	 * @param WCGroup $group Collections must also match this group.
	 * @return WCCollection[] Returns a list of found collections.
	 */
	public function collectionsLike($keywords, WCGroup &$group) {
		//
		// Setting the default value to be returned.
		$out = array();
		//
		// Creating a statement to look for matches.
		// @{
		$stmt = null;
		$stmtId = __CLASS__."::".__FUNCTION__;
		if($this->_db->has($stmtId)) {
			$stmt = $this->_db->get($stmtId);
		} else {
			$query = "select  *\n";
			$query .= "from    {$this->_dbprefix}collections\n";
			$query .= "where   col_group = :group\n";
			$query .= " and    lower(col_name) like :filter\n";

			$stmt = $this->_db->prepare($stmtId, $query);
		}
		// @}
		//
		// Asking for collections.
		// @{
		$params = array(
			":group" => $group->id,
			":filter" => "%".strtolower($keywords)."%"
		);
		if($stmt->execute($params)) {
			//
			// Adding all findings.
			foreach($stmt->fetchAll() as $row) {
				$collection = $this->item($row["col_id"], $group);
				$out[] = $collection;
				foreach($collection->collectionsFull() as $child) {
					$out[] = $child;
				}
			}
		}
		// @}
		//
		// Sorting results by their paths.
		uasort($out, "WCCollection::PathSort");
		//
		// Returning the list of found collections.
		return $out;
	}
	/**
	 * This method allows to clear any list cached by this holder.
	 */
	public function resetCache() {
		//
		// Asking parent class WCGHolder to clean the cache it knows,.
		parent::resetCache();
		//
		// Cleaning the list of top collections.
		$this->_topItems = array();
	}
	/**
	 * This method allows to get the list of top collection of a group.
	 *
	 * @param WCGroup $group Group to use as a filter for the top collections
	 * to return.
	 * @return WCCollection[] Returns the list of top collections.
	 */
	public function topItems(WCGroup &$group) {
		//
		// Checking if a list for the requested group was already loaded.
		if(!isset($this->_topItems[$group->id])) {
			//
			// Creating a list to hold the list of  top collections
			// for the requested group.
			$this->_topItems[$group->id] = array();
			//
			// Checking every item associated with the group.
			foreach($this->items($group) as $item) {
				//
				// If a collection has no parent it is considered
				// to be a top collection.
				if(!$item->parent) {
					//
					// Storing the collection on the list
					// assigned to the requested group.
					$this->_topItems[$group->id][] = $item;
				}
			}
		}
		//
		// Returning the list of top collections for the correct group.
		return $this->_topItems[$group->id];
	}
	//
	// Public class methods.
	/**
	 * This class method allows to get the sole instance of this holder.
	 *
	 * @return WCCollectionsHolder Returns the singleton instance of this
	 * class.
	 */
	public static function Instance() {
		//
		// Checking if there's no instance yet.
		if(!isset(self::$_Instance)) {
			$c = __CLASS__;
			//
			// Creating the sole instance.
			self::$_Instance = new $c;
		}
		//
		// Returning the class instance.
		return self::$_Instance;
	}
}
?>